package ioc

import (
	"context"
	"fmt"
	"github.com/spf13/viper"
	"go.mongodb.org/mongo-driver/event"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.uber.org/zap"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/plugin/opentelemetry/tracing"
	"gorm.io/plugin/prometheus"
	"jk-time/webook/internal/dao"
	"jk-time/webook/pkg/gormx/callbacks"
	"time"
)

func InitDB() *gorm.DB {
	type Config struct {
		User     string `yaml:"user"`
		Password string `yaml:"password"`
		Host     string `yaml:"host"`
		Dbs      string `yaml:"dbs"`
	}

	user := viper.GetString("db.user")
	password := viper.GetString("db.password")
	host := viper.GetString("db.host")
	dbs := viper.GetString("db.dbs")
	sqlConfig := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc"+
		"=Local", user, password, host, dbs)
	db, err := gorm.Open(mysql.Open(sqlConfig))
	if err != nil {
		panic(err)
	}
	//监听变化
	//dao.NewGormUserDAO(func() *gorm.DB {
	//	viper.OnConfigChange(func(in fsnotify.Event) {
	//		db, err = gorm.Open(mysql.Open(sqlConfig))
	//		pt := unsafe.Pointer(&db)
	//		atomic.StorePointer(&pt,unsafe.Pointer(&db))
	//	})
	//	return db
	//})
	err = db.Use(prometheus.New(prometheus.Config{
		DBName:          "webook",
		RefreshInterval: 15,
		StartServer:     false,
		MetricsCollector: []prometheus.MetricsCollector{
			&prometheus.MySQL{
				VariableNames: []string{"thread_running"},
			},
		},
	}))
	if err != nil {
		zap.L().Error("gorm监控失败:", zap.Error(err))
	}

	callback := prome.NewCallback(
		"gorm",
		"query",
		"gorm_query_time",
		"统计gorm的执行时间",
		"gorm-1")

	err = db.Use(callback)
	if err != nil {
		zap.L().Error("gorm callback监控失败:", zap.Error(err))
	}

	db.Use(tracing.NewPlugin(tracing.WithDBName("webook"), tracing.WithQueryFormatter(func(query string) string {
		zap.L().Debug("", zap.String("query", query))
		return query
	}),
		//不要记录metrics
		tracing.WithoutMetrics(),
		//不要查询参数
		tracing.WithoutQueryVariables(),
	))

	err = dao.InitTables(db)
	if err != nil {
		panic(err)
	}
	return db
}

func InitMongoDB() *mongo.Client {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	monitor := &event.CommandMonitor{
		//命令执行前
		Started: func(ctx2 context.Context, startedEvent *event.CommandStartedEvent) {
			fmt.Println(startedEvent.Command)
		},
	}
	//设置客户端连接配置
	clientOptions := options.Client().ApplyURI("mongodb://192.168.71.130:27017").SetMonitor(monitor)
	//建立连接
	client, err := mongo.Connect(ctx, clientOptions)
	if err != nil {
		panic(err)
	}
	return client
}
